package intercept

import (
	"bytes"
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
	"net/http"
	"regexp"
	"strings"
	"wrblog-api-go/app/common/token"
	"wrblog-api-go/config"
	"wrblog-api-go/pkg/errs"
	"wrblog-api-go/pkg/mylog"
	"wrblog-api-go/pkg/result"
	"wrblog-api-go/pkg/status"
)

// "/api/v1" + config.Conf.ConfigInfo.FilePrefix + "/*",
var noPath = []string{"/", "/favicon.ico", "/api/v1/demo/*", "/api/v1/auth/*", "/swagger/*"}

// CheckHttp 拦截请求、并构建可重复读body
func CheckHttp(c *gin.Context) {
	// 请求基本信息
	method := c.Request.Method
	path := c.Request.URL.Path
	// 读取请求体（缓存一份，否则后面就读不到了）
	var bodyBytes []byte
	if c.Request.Body != nil {
		bodyBytes, _ = io.ReadAll(c.Request.Body)
		c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) // 重置流，后续还能用
	}
	// 查询参数
	queryParams := c.Request.URL.RawQuery
	if strings.Contains(path, "upload") {
		// 日志打印
		mylog.MyLog.Debugf("【请求】%s %s\n------>文件上传",
			method,
			path,
		)
	} else {
		// 日志打印
		mylog.MyLog.Debugf("【请求】%s %s\n------>Query: %s\n------>Body: %s",
			method,
			path,
			queryParams,
			string(bodyBytes),
		)

	}
	// 执行下一个 handler
	c.Next()
	// 打印响应状态码（可选）
	statusCode := c.Writer.Status()
	mylog.MyLog.Debugf("【响应】%s %s - %d", method, path, statusCode)
}

// CheckIp ip拦截
func CheckIp(c *gin.Context) {
	//ip白名单
	if !WhiteIp(c.ClientIP()) {
		mylog.MyLog.Error(fmt.Sprintf("该Ip无权访问:%s", c.ClientIP()))
		result.Wrap(http.StatusForbidden, fmt.Sprintf("该Ip无权访问:%s", c.ClientIP())).Json(c)
		c.Abort() //停止执行
	}
	c.Next()
}

// CheckToken token拦截
func CheckToken(c *gin.Context) {
	path := c.Request.RequestURI
	//判断拦截的路由
	loginUser, ok := token.CheckLogin(c)
	if ok {
		c.Set("loginUser", loginUser)
	}
	if !NotIntercept(path) {
		if !ok {
			result.Fail(errs.New(http.StatusUnauthorized, fmt.Sprintf("请求访问：%s,认证失败！", path))).Json(c)
			c.Abort() //停止执行
		}
	}
	c.Next() //继续执行
}

// CrossOriginMiddleware 跨域设置
func CrossOriginMiddleware(c *gin.Context) {
	method := c.Request.Method
	origin := c.Request.Header.Get("Origin")
	if origin != "" {
		// 允许特定来源跨域请求
		c.Header("Access-Control-Allow-Origin", origin)
		c.Header("Access-Control-Allow-Credentials", "true")
	}
	c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
	c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type,X-File-Name")
	if method == "OPTIONS" {
		c.AbortWithStatus(status.NoContent)
	}
	c.Next()
}

// WhiteIp 不拦截的ip(ip白名单)
func WhiteIp(ip string) bool {
	arr := config.Conf.ConfigInfo.IpWhites
	if len(arr) == 0 {
		return true
	}
	//默认本机不拦截
	arr = append(arr, "127.0.0.1", "::1")
	for _, element := range arr {
		if ip == element || element == "0.0.0.0" {
			return true
		}
	}
	return false
}

// NotIntercept 判断路由是否拦截
func NotIntercept(path string) bool {
	//不拦截的地址
	for _, url := range noPath {
		regexPattern := convertToRegex(url)
		matched, err := regexp.MatchString(regexPattern, path)
		if err != nil {
			continue
		}
		if matched {
			return true
		}
	}
	return false
}

// 将URL通配符转换为正则表达式
func convertToRegex(pattern string) string {
	// 转换*为正则表达式的.*
	re := regexp.MustCompile(`\*+`)
	pattern = re.ReplaceAllString(pattern, ".*")
	// 在模式的开始和结束处加上^和$
	return "^" + pattern + "$"
}
